package DesignPatterns.singleton;

/**
 * 双重检查锁
 * 这被认为是一个没有缺点的单例模式，实际上他只是保证了在使用构造器创建对象时完全实现了单例，且保证了锁的粒度足够小的同时保证了线程安全性。但是我们知道创建对象java里还可以使用Cloneable的clone方法，还可以使用反射，还可以使用反序列化这些操作。这些操作其实一样式可以绕可这个单例的。
 * 优点：懒加载、线程安全，尽最大努力降低了锁的粒度
 * 缺点：相比于静态内部类效率稍微差点，但是生产可用
 */
public class Single6 {
    private static volatile Single6 single;

    private Single6() {
    }

    public static Single6 getInstance() {
        // 这里加if可已在高并发时省去大部分排队加锁的操作，是有必要的
        if (single == null) {
            // 这里可能存在多个线程都进入的场景，所以下面的同步代码块可能存在执行多次的场景
            synchronized (Single6.class) {
                // 因为这段代码可能存在多次执行，但是同一时间只有一个会执行，所以再进行一次非空判断就解决了问题
                if (single == null) {
                    single = new Single6();
                    return single;
                }
            }
        }
        return single;
    }
}

